
上一篇提到,這套便當系統不是從 GAS、React 或 Cloudflare 開始的。
在那些東西出現以前,公司裡就已經有一套真的有人在用的內部訂餐系統。
它可以:
當我決定做新的手機版時,第一個問題不是:
我要用什麼框架?
也不是:
要不要用 React?
而是:
舊系統裡,到底有哪些行為是新版不能弄丟的?
如果這件事沒有先搞清楚,重做很容易變成:
畫面更漂亮了,
技術更新了,
但使用者原本習慣的流程卻壞掉了。
我後來才慢慢發現:
重做 Legacy System,第一步不是先寫 Code,而是先把需求從舊系統裡挖出來。
拿 Day 1 的舊畫面來看,乍看之下很簡單。
例如訂餐頁可能只看到:
如果只是照著畫面重做,很容易理解成:
好,那新版把這些欄位做出來就好了。
但開始移轉之後,問題會變成完全不同的樣子。
例如:
如果未來開始有登入機制,那姓名到底是:
原本舊系統可能完全不需要回答這些問題。
因為在當時的使用環境裡,大家知道「這個名字是誰」。
但一旦系統開始往手機、登入、身份綁定走,
這個原本看起來只是一個文字欄位的東西,就會變成身份模型的一部分。
舊系統裡有取餐樓層。
看起來只是:
1F
9F
但它背後其實連著實際流程。
因為最後便當不是只要知道總共有幾份。
還需要知道:
1 樓要幾份?
9 樓要幾份?
這會直接影響最後的發餐方式。
移轉時要保留的不是:
資料庫裡有一個
floor欄位。
而是:
統計結果必須能依取餐樓層正確分組。
兩者看起來很像,實際上完全不同。
前者是資料結構。
後者才是 Business Rule。
Day 1 的另一張畫面,是當日訂餐統計。
表面上看起來可能只是:
某餐點:5
另一餐點:8
1F:6
9F:7
技術上可能只是幾個 SUM()、GROUP BY。
但這個頁面的用途是:
它的數字最後會被拿來向店家下單。
這件事讓它從「統計畫面」變成會直接影響日常流程的資料。
如果統計錯一份,
結果不是 Dashboard 長得不好看,
而是真的可能有一個人沒便當吃。
如果要重新整理需求,我會把:
功能:顯示統計
改寫成:
對指定日期的有效訂單進行統計,
依餐點與取餐樓層彙總,
並作為實際向店家下單的依據。
這就是我後來很重視的一件事:
不要只記錄畫面做什麼,要記錄這個畫面為什麼存在。
舊系統後來加入預付餘額。
一開始需求非常單純:
大家一次先繳一些錢,訂便當就從裡面扣。
畫面上可能就只是一個數字:
餘額:700
如果只看 UI,很容易把需求理解成:
使用者有一個
balance欄位。
訂餐時:
balance = balance - price
取消時:
balance = balance + price
看起來好像就結束了。
但實際維護之後,就會開始出現問題:
這時候才會發現:
「餘額」不是一個數字,而是一段歷史的結果。
這個觀念後來也直接影響我之後怎麼設計 Balance Ledger。
但在第一次移轉時,我還沒有把事情做到這麼完整。
當時更重要的是先意識到:
這個看起來只有一欄的功能,不能只當成一欄資料搬過去。
為了避免「看到什麼就重做什麼」,我現在會把需求分成四類。
這個分類不只適用便當系統,很多 Legacy Migration 也能拿來用。
這些是使用者已經依賴的功能。
例如:
這一類的重點不是:
介面要長得一樣。
而是:
新版必須保留同樣的業務結果。
有些東西是舊系統可以用,但新版本有機會做得更好。
例如:
這類需求可以重新設計。
但改善前還是要問:
使用者原本為什麼這樣操作?
不要只是因為新版比較漂亮,就把原本有效率的流程改掉。
這些是推動重做的原因。
例如:
這一類不能假裝成 Legacy Parity。
它就是新的需求。
而新需求越多,
越代表這次不是單純移植。
而是:
在保留舊行為的前提下,重新定義下一版系統。
這一類反而很重要。
因為一旦開始重做,很容易冒出很多:
既然都要做了,不然順便……
例如:
每一個都好像有道理。
但全部一起做,第一版通常永遠出不來。
更實際的做法是:
先把「下一版一定要解決什麼」和「現在不要解決什麼」切清楚。
這也是後來我在 Agent Workflow 裡很常用 Explicit Exclusions 的原因。
範圍沒有寫清楚,
人會順手多做,
AI Agent 更會。
如果把當時的舊系統重新整理一次,大概會像這樣:
| 舊系統能力 | 表面上看到的功能 | 要保留的規則 | 分類 |
|---|---|---|---|
| 未來 21 天訂餐 | 日期選擇 | 只能在允許的日期範圍內下單 | Must Keep |
| 過去 7 天紀錄 | 歷史查詢 | 已發生訂單必須能追溯 | Must Keep |
| 取餐樓層 | 1F / 9F | 統計必須依實際取餐樓層分組 | Must Keep |
| 當日統計 | 數量統計 | 數字會直接作為店家下單依據 | Must Keep |
| 預付餘額 | 一個金額 | 訂餐、取消後金額必須一致 | Must Keep |
| 手機使用 | 新介面 | 不再依賴固定公司電腦 | New |
| 多店家 | 店家選擇 | 店家、菜單、價格不再是固定值 | New |
| UI 重整 | 畫面改善 | 不影響既有訂餐流程 | Improve |
這張表對我來說,比先畫新版 UI 更重要。
因為它開始把:
舊網站長什麼樣
轉成:
新版必須保證什麼。
只有「需求」還不夠。
像這種描述:
取餐樓層要正常。
幾乎沒辦法驗收。
如果要真的拿來重做,我會希望它至少變成:
Given
使用者的取餐樓層為 9FWhen
使用者成功提交一份便當訂單Then
該訂單保存pickup_floor = 9FAnd
當日統計的 9F 數量增加 1And
1F 的統計數量不受影響
這就從一個模糊的需求,
變成可以驗收、也可以測試的行為。
同樣的概念也可以套到餘額:
Given
使用者目前餘額為 500 元When
成功訂購一份 100 元便當Then
訂單成功建立And
剩餘餘額為 400 元
如果還有取消流程:
Given
該 100 元訂單已成立When
在允許取消的條件下成功取消Then
訂單狀態變更And
100 元必須正確回到使用者餘額
當需求開始寫到這個程度,
它才開始具備「可以移轉」的條件。
如果今天完全人工重寫,
工程師在做的時候可能還會邊看、邊問、邊修。
但如果把需求直接丟給 AI Agent:
幫我把舊訂餐網站重做成手機版。
它很可能做出一個:
看起來完全合理,但行為已經變掉的系統。
因為 AI 看得到:
但它不一定知道這個欄位為什麼存在,也不知道哪個看起來很奇怪的行為,可能正是公司已經用了兩年的流程。
到了 AI 時代,我反而更重視一件事:
把「不能被猜錯的東西」寫下來。
而且不一定要寫成幾十頁需求文件。
有時候一張 Feature Inventory,
幾條 Business Rule,
加幾個 Acceptance Criteria,
就已經能大幅降低重做時的誤差。
如果把今天這篇濃縮成一個流程,我現在會這樣做:
1. 看舊系統
↓
2. 列 Feature Inventory
↓
3. 找 Hidden Business Rules
↓
4. 分成 Must Keep / Improve / New / Non-goal
↓
5. 重要行為寫成 Acceptance Criteria
↓
6. 最後才開始重新選技術與實作
這比:
看一下舊畫面
↓
開始寫新版
慢一點。
但通常會少掉很多後面的返工。
尤其當舊系統已經有人在用、有正式資料、有歷史流程時,
這個步驟的重要性會變得更高。
因為不能弄丟的不是舊畫面的 CSS,而是那些已經存在於系統和使用者之間、卻從來沒有人正式寫下來的規則。
需求盤點完成之後,才輪到技術選擇。
當時我要的很簡單:
第一版手機化最後選擇了:
Google Apps Script + Google Sheets。
下一篇就來看:
Day 3|第一版手機化,為什麼我會選 GAS + Google Sheets?